use crate::{
    c::{
        osMutexAcquire, osMutexAttr_t, osMutexId_t, osMutexNew, osMutexPrioInherit,
        osMutexRecursive, osMutexRelease, osMutexRobust, osRtxMutex_t, osWaitForever,
    },
    utils::Align8Store,
};
use core::ptr::null_mut;

const CB_SIZE: usize = size_of::<osRtxMutex_t>();

pub struct Mutex {
    cb_mem: Align8Store<CB_SIZE>,
    id: osMutexId_t,
}

pub struct MutexGuard<'a> {
    m: &'a Mutex,
}

impl<'a> Drop for MutexGuard<'a> {
    fn drop(&mut self) {
        unsafe { osMutexRelease(self.m.id) };
    }
}

impl Mutex {
    pub const fn default() -> Self {
        Self {
            cb_mem: Align8Store::new(),
            id: null_mut(),
        }
    }

    pub fn new(&mut self, name: &str) {
        let attr = osMutexAttr_t {
            name: name.as_ptr() as *const i8,
            attr_bits: osMutexPrioInherit | osMutexRecursive | osMutexRobust,
            cb_mem: self.cb_mem.raw_ptr(),
            cb_size: CB_SIZE as u32,
        };
        self.id = unsafe { osMutexNew(&attr) };
        assert!(self.id != null_mut(), "mutex new fail");
    }

    pub fn lock<'a>(&'a self) -> MutexGuard<'a> {
        unsafe { osMutexAcquire(self.id, osWaitForever) };
        MutexGuard { m: &self }
    }
}
